home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / demos / 275 / pascal / fastread.doc < prev    next >
Encoding:
Text File  |  1988-07-14  |  14.2 KB  |  467 lines

  1.      1    1    1    1    1    1    1    1    1    1    1    1    ]    ]
  2.  
  3.  
  4.                     Eric's Fast Text Readln
  5.                         By Eric W. Wedaa
  6.                         4620 E 17th St.
  7.                         Tucson AZ, 85711
  8.                           Bix :EWedaa
  9.                         CIS :76515.2274
  10.                            Feb 21, 1988
  11.  
  12.  
  13.      I'll be honest here.  I LOVE Pascal.  It's a nice neat little 
  14.  
  15. language for writting programs, quite unlike some of the anarchist 
  16.  
  17. languages (C, assembly) or dinosaurs (B.A.S.I.C.)  But there are 
  18.  
  19. times when even I'll admit that Personal Pascal has problems.  The 
  20.  
  21. most glaring problem is doing a READ or a READLN.  
  22.  
  23.  
  24.      Now don't get me wrong, they work just fine in most 
  25.  
  26. instances.  But they can be the most annoying function of Pascal 
  27.  
  28. when I have to read in 200K of text file from a RAM disk, or even 
  29.  
  30. worse, 200K off of a floppy disk. I can go to the coffee shop for 
  31.  
  32. lunch while I'm reading in all that text.  Thankfully, O.S.S. has 
  33.  
  34. given us an extension that lets us call some of the GEMDOS 
  35.  
  36. routines from our code.
  37.  
  38.  
  39.                         My New Routines
  40.  
  41.      Well, I finally got sick of going to the coffee shop all the 
  42.  
  43. time.  (The waitress's avoid me now, since they all know I'm a 
  44.  
  45. lousy tipper.)  In the FASTREAD folder on the disk, you'll find 
  46.  
  47. my answer to the coffee shop blues.  This program is a Pascal 
  48.  
  49. version of GEMDOS $3C, $3D, $3E, $3F, $40, $42 (Create, Open, 
  50.  
  51. Close, Read, Write, Seek).  Using these routines in your program 
  52.  
  53. will make your READLN's between 7 and 12 times faster than the 
  54.  
  55. Pascal supplied READLN.
  56.  
  57.  
  58.      One VERY new routine that doesn't exist in any other language that I 
  59.  
  60. know of is the F_Breadln routine.  This was something I developed for one 
  61.  
  62. of my programe and thought others might find it handy.  What it is a 
  63.  
  64. backwards readln routine.  Instead of buffering the input yourself, (With 
  65.  
  66. all of those headaches, it uses the internal file buffer to do that for 
  67.  
  68. us.  If you need to scan backwards several lines, just use this routine.  
  69.  
  70. It passes the strings back to you in a forward order. ("Hi there!" 
  71.  
  72. instead of "!ereht iH".  You do have to be carefull of reading past the 
  73.  
  74. start of the file though.  Weird things happen when you do.  If you use 
  75.  
  76. this routine in your program, you need to check for an SOF (Start of 
  77.  
  78. file) flag.  To get around the fact that this flag is set when you first 
  79.  
  80. open the file, use something similar to the following code:
  81.  
  82.      primed: boolean;
  83.           |
  84.           |
  85.           |
  86.      begin;
  87.           |
  88.         Primed := FALSE;
  89.         While (Not EOF (file_buffer))
  90.           and ((not primed) and (Not SOF (File_buffer)) do begin;
  91.                Primed := TRUE;
  92.           |
  93.           |
  94.           |
  95.           ETC.
  96.  
  97.  
  98.      This will get you into the file successfully. 
  99.  
  100.  
  101.                        Using the Routines
  102.  
  103.      For those of you interested in just using these routines, 
  104.  
  105. this section is all you'll ever need to know.  You'll need to put 
  106.  
  107. the constants, types, and the routines from FASTREAD.PAS into your 
  108.  
  109. program.  Allthough they don't need to be global for your program, 
  110.  
  111. they do need to be declared in the same block of code that you'll 
  112.  
  113. be using the routines from.  (Which probably means globally.)
  114.  
  115.  
  116.      Now when you want to have a file for just reading from the 
  117.  
  118. disk, instead of declaring it as type FILE OF TEXT, just declare 
  119.  
  120. it instead as type BUFFER.  Whenever you want to perform an action 
  121.  
  122. a disk file, just use the matching function from the chart below.  
  123.  
  124. You will still be passing parameters in the same order as with the 
  125.  
  126. Pascal functions.  The two error routines require you to pass the 
  127.  
  128. buffer to them as well.  You MUST do your own error checking with 
  129.  
  130. these routines!
  131.  
  132.      Fast Read Subroutines
  133.  
  134.      Pascal                                 Fast Read
  135.      Rewrite (File of TEXT, File name)      F_Rewrite(Buffer, File name)
  136.      Writeln (File of TEXT, String)         F_Writeln(Buffer, String)
  137.      Write   (File of TEXT, String)         F_Write(Buffer, String)
  138.      Reset   (File of TEXT, File name)      F_Reset (Buffer, File name)
  139.      Readln  (File of TEXT, String)         F_Readln (Buffer, String)
  140.      Seek    (File of TEXT, Integer)        F_RSeek(Buffer, Pos):Boolean
  141.      Close   (File of TEXT)                 F_Close (Buffer)     
  142.      Eof     (File of TEXT)                 F_Eof (Buffer)  
  143.      IO_Result                              F_Io_Result (Buffer)
  144.                                             F_Error (Buffer)
  145.                                             F_Breadln(Buffer, String);
  146.  
  147.  
  148.      NOTE: F_RSeek is a function returning a BOOLEAN value.  This 
  149.  
  150. is true if the seek suceeded, and false if it failed.  This is 
  151.  
  152. for use while reading files ONLY!  The File starts at 0, not 1.
  153.  
  154.  
  155.      Notice though that these routines are set up just for 
  156.  
  157. READING or WRITING from or to a disk based file. (Ram, Hard, or 
  158.  
  159. Floppy disk.)  This is not for reading from any of the ports, or 
  160.  
  161. more likely, to try to write to any of the ports.
  162.  
  163.  
  164.      If you don't want to be reading in 255 byte strings, change 
  165.  
  166. the STRING_SIZE constant to the right size.
  167.  
  168.  
  169.                         Why it's Faster
  170.  
  171.      Doing a F_Readln or F_Writeln is increadibly fast.  7 to 12 
  172.  
  173. times faster in some cases.  Great, but why?  It has mainly to do 
  174.  
  175. with two areas we can't touch.  The first is the file buffer 
  176.  
  177. size.
  178.  
  179.  
  180.      When you declare a text file, Pascal only sets aside a small 
  181.  
  182. area of memory as a file buffer.  When it's used, it has to call 
  183.  
  184. the disk up again and read another sector or two.  In other words, 
  185.  
  186. it's always calling the disk, which entails spinning up the drive, 
  187.  
  188. finding the sector, reading the sector, and turning the drive off.  
  189.  
  190.  
  191.      When you use the Fast Read routines, we try and avoid the 
  192.  
  193. time spinning up the disk and searching for tracks and sectors 
  194.  
  195. from a stopped disk.  Instead of reading or writing in 512 bytes 
  196.  
  197. at a time, we read or write in 15,000 bytes at a time.  This way 
  198.  
  199. we don't lose time starting everything over again.
  200.  
  201.  
  202.      The second reason is inherent in the way Pascal handles I/O.  
  203.  
  204. When you call a Pascal READLN, you can ask it to read in any kind 
  205.  
  206. of data.  Integers, strings, booleans, reals, or records.  Not 
  207.  
  208. only that, but you have them in your READLN in any order, and in 
  209.  
  210. any quantity.  In other words, your I/O requests can be as sloppy 
  211.  
  212. as you want them to be.
  213.  
  214.  
  215.      So if you use the following READLN--->READLN (in_File, 
  216.  
  217. An_Integer1, A_Real1, A_String1, A_Boolean, A_Real2);<--- then 
  218.  
  219. you're asking for time trouble.  It has to first see if In_File is 
  220.  
  221. a file variable or not, and then it has to go through each of the 
  222.  
  223. variables seeing what type they are and the specifics on how to 
  224.  
  225. read each of them in.  All this takes a lot of time.
  226.  
  227.  
  228.      With the Fast Read routines, we avoid all of that. It knows 
  229.  
  230. that it's only reading or writing in strings from a text file.  
  231.  
  232. It knows the maximum string size allready.  In other words, 
  233.  
  234. specialization is what makes this routine faster.  Of course it 
  235.  
  236. costs a few more bytes, but if you're doing a lot of reading from 
  237.  
  238. text files, it makes it worth it.  
  239.  
  240.  
  241.                        Development Details
  242.  
  243.  
  244.      These routines are all based on GEMDOS functions $3C, $3D, 
  245.  
  246. $3E, $3F, $40 (Create, Open, Close, Read, Write).  Allthough 
  247.  
  248. these GEMDOS functions have been described before, they have only 
  249.  
  250. been presented as a way to read in screen information, or large 
  251.  
  252. amounts of array information.  Nothing on how to extract or 
  253.  
  254. insert strings from a one dimensional array.
  255.  
  256.  
  257.      So I had the information on loading a plain vanilla one-
  258.  
  259. dimension array.  For strings, this is almost useless.  There's 
  260.  
  261. just to much information you have to keep track of to read in a 
  262.  
  263. string to have a bunch of individual variables.  So after 
  264.  
  265. figuring out what I needed to keep track of, I declared the 
  266.  
  267. following record: 
  268.  
  269.    Buffer = RECORD
  270.       Buffer_Contents : Contents ; { Contents of the buffer.        }
  271.       File_Handle : INTEGER ; {      File handle.                   }
  272.       Error_Number : INTEGER ; {     Error Number if error occured. }
  273.       No_Error : BOOLEAN ; {         Was there no error occuring?   }
  274.       Buffer_Pos : LONG_INTEGER ; {  Position to be read next.      }
  275.       Buffer_Len : LONG_INTEGER ; {  How long is the buffer?        }
  276.       Last_Buffer : BOOLEAN ; {      Is this the last buffer?       }
  277.       Eof_Buffer : BOOLEAN ; {       Are we at the end of the file? }
  278.       Reading_File : BOOLEAN ; {     Are we reading this file?      }
  279.       Fast_Return : CHAR ; {         Return character.              }
  280.       Fast_Line_Feed : CHAR ; {      Line feed character.           }
  281.       Pos_In_File : LONG_INTEGER ; { What is the char count to the  }
  282. {                                    Start of this buffer?          }
  283.       End_Pos : LONG_INTEGER ; {     What is the char count to the  }
  284. {                                    end of this buffer?            }
  285.  
  286.     END ; {of type buffer}
  287.  
  288.  
  289.      Now all I had to do was pass a single variable around, 
  290.  
  291. instead two or eight variables.  (Also a neat way to speed up the 
  292.  
  293. routines.)  
  294.  
  295.  
  296.      Next, I had to write the GEMDOS calls, F_Create, F_Open, 
  297.  
  298. F_Read, F_Write, and F_Close.  These came out of the O.S.S. 
  299.  
  300. release on using GEMDOS calls.  (Available on their BBS, BIX, and 
  301.  
  302. CIS.)
  303.  
  304.  
  305.      Then came the tricky part, writting the F_Reset, F_Rewrite, 
  306.  
  307. F_Readln, and F_Writeln routines.  F_Rewrite converts the file 
  308.  
  309. name into C format and the calls F_Create (GEMDOS $3C.)  It then 
  310.  
  311. initializes it's variables depending on whether an error occurred 
  312.  
  313. or not.
  314.  
  315.  
  316.      F_Reset wasn't to hard once I figured out what I wanted it 
  317.  
  318. to do.  It has to convert the file name into C format in order to 
  319.  
  320. pass it correctly.  It then calls GEMDOS $3D to open the file.  
  321.  
  322. If it opens without an error, it then loads the Buffer_Contents 
  323.  
  324. array.
  325.  
  326.  
  327.      The F_Read_File routine is where we load the buffer.  If it 
  328.  
  329. successfully loads the buffer, it initializes the variables in the 
  330.  
  331. record.  It then checks to see if it was the end of the file, and 
  332.  
  333. sets Last_Buffer to TRUE or FALSE, as is appropriate.  If an error 
  334.  
  335. occurs, it sets all the variables to show this occurance.
  336.  
  337.  
  338.      The hard part was to write the F_Readln routine.  The first 
  339.  
  340. part I wrote was the area to just move characters from the buffer 
  341.  
  342. to the text string until we hit the last position in the buffer, 
  343.  
  344. or a Carriage Return character, or the string is filled.  
  345.  
  346.  
  347.      Then came the IF-THEN-ELSE statements to determine what to do 
  348.  
  349. next.  The first in the series checks to see if the loop was left 
  350.  
  351. because it found a Return.  If this was the case, it sets the 
  352.  
  353. length of the string equal to Counter.  It then increments the 
  354.  
  355. Buffer_Pos by two to pass the Return and the Line Feed.  If 
  356.  
  357. Buffer_Pos is greater than the length of the buffer it reloads 
  358.  
  359. the buffer again with a call to F_Read_File.  It then resets 
  360.  
  361. Buffer_Pos to one or two to set the position to the first 
  362.  
  363. character in the buffer.  It sets it to one if the first char- 
  364.  
  365. acter isn't a Line Feed, and to two if it is.
  366.  
  367.  
  368.      If the program flow falls through the above test, it checks 
  369.  
  370. the next IF/THEN.  This checks to see if the loop was exited 
  371.  
  372. because the string was full.  If this was the case, then it sets 
  373.  
  374. the length of the string equal to counter and leaves Buffer_Pos 
  375.  
  376. alone.
  377.  
  378.  
  379.      If the programs passes that IF/THEN it checks to see if the 
  380.  
  381. string loading was interupted because it ran out of buffer, and 
  382.  
  383. there was more information in the file (Not Last_Buffer.)  If this 
  384.  
  385. was the case it reloads the buffer again and calls itself to 
  386.  
  387. finish reading the file.  If an error occurs while reloading the 
  388.  
  389. buffer, it sets the string length to Count, and exits the routine.
  390.  
  391.  
  392.      And lastly, it checks if the loop was done because it ran out 
  393.  
  394. of buffer and there wasn't any more information in the file.  If 
  395.  
  396. this was the case, it sets the string length to Count again, and 
  397.  
  398. sets EOF_Buffer to true.  It then exits the routine. 
  399.  
  400.  
  401.      The next set of routines are the Fast_Write routines.  These 
  402.  
  403. were written after the Fast_Read routines were done.  (Hence the 
  404.  
  405. program name.)  These routines are F_Writeln and F_Write.
  406.  
  407.  
  408.      F_Writeln was initially the F_Readln routine.  I copied it 
  409.  
  410. once and modified it a bit.  Instead of pulling characters from 
  411.  
  412. the main array (Buffer_Contents) it pushes them onto it.  This 
  413.  
  414. allowed me to remove one of the loop tests (Look for Return) 
  415.  
  416. since there wasn't a Return in sight.  When it exits the loop it 
  417.  
  418. sets Buffer_Len to the new length.  If there's more room in 
  419.  
  420. Buffer_Contents it pushes a Ruturn/Line Feed onto the array.  
  421.  
  422. Otherwise, it writes out the array and adds a Return/Line Feed 
  423.  
  424. combination onto the start of the next array.
  425.  
  426.  
  427.      The F_Eof, F_Error, and F_Error_Number routines were written 
  428.  
  429. just to help hide the data structure a little better.  A user 
  430.  
  431. could (if s/he is really desperate to save time.) directly access 
  432.  
  433. the contents of the record instead of calling these routines.  
  434.  
  435.  
  436.      But I just finished a programming class where the teacher was 
  437.  
  438. big on "Hiding Data Structures"  So I decided to hide the 
  439.  
  440. structure a little bit.  That, and it makes it easier to convert 
  441.  
  442. my programs over to these routines.  All I had to do was a global 
  443.  
  444. search and replace through my files to change Pascal routines into 
  445.  
  446. Fast routines.
  447.  
  448.  
  449.      For a weekend project, this wasn't to hard to finish up.  I 
  450.  
  451. think that this program shows a little bit more of the range of 
  452.  
  453. things that can be accomplished with O.S.S. Pascal.  With access 
  454.  
  455. like this to the internal TOS and GEM routines, Who needs C?  
  456.  
  457. Certainly not me!
  458.  
  459.  
  460. References:
  461.  
  462.     Personal Pascal
  463.      O.S.S.
  464.      1221B Kentwood Avenue
  465.      San Jose, CA, 95129
  466.      408-446-3099
  467.